package com.itlong.cloud.utils.data.handler;

import com.itlong.cloud.POJO.DTO.BaseDTO;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.annotation.ItlField;
import com.itlong.cloud.annotation.ItlTables;
import com.itlong.cloud.thrown.DataAccessException;
import com.itlong.cloud.utils.date.DateUtil;
import com.itlong.cloud.utils.page.Page;
import com.itlong.cloud.utils.words.StringHandlerUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * <desc>
 *      sql帮助类
 * </desc>
 *
 * @createDate 2017/9/13
 */
public class SqlUtil {

    protected static final Logger LOG = LoggerFactory.getLogger(DataAccessException.class);


    /**
     * <desc>
     *      将实体类转换为map格式的param
     * </desc>
     *
     * @param obj 待转换的bean
     * @return
     * @author Jiaqi.X
     * @createDate 2017/09/21
     */
    public static <T> Map<String, Object> convertBeanToMapParams(T obj) throws Exception {
        Map<String, Object> beanMap = new HashMap<>();
        try {
            putDeclaredFieldsToMap(obj, obj.getClass(), beanMap);

        } catch (Exception e) {
            throw new Exception("将实体转换为map格式的param异常！", e);
        }
        return beanMap;
    }

    /**
     * <desc>
     *      将某一对象所有声明字段放入map中（包括父类声明的字段）
     * <desc/>
     *
     * @param obj 实例对象
     * @param clazz 实例对象的类对象或其父类对象
     * @param beanMap map对象，外部传入
     * @return
     * @author Chunjian.G
     * @createDate 2017-10-19
     */
    private static void putDeclaredFieldsToMap(Object obj, Class clazz, Map beanMap) throws Exception {
        //先解析子类的参数
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            //获取get属性方法名
            String name = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
            //获取属性的类型
            String type = field.getGenericType().toString();
            Object value;
            Method m = obj.getClass().getMethod("get" + name);
            value = m.invoke(obj);
            if (type.equals("class java.lang.String")) {
                //调用getter方法获取属性值
                beanMap.put(field.getName(), StringHandlerUtil.getStringOrNull((String) value));
            }else{
                if (type.equals("class java.util.Date")) {
                    beanMap.put(field.getName(), value != null && !value.toString().equals("") ?
                            StringHandlerUtil.getStringOrNull(DateUtil.fomatDate((Date) value)) : null);
                } else {
                    beanMap.put(field.getName(), value != null && !value.toString().equals("") ? value : null);
                }
            }
        }
        //继续解析其父类参数
        if (null != clazz.getSuperclass() && !Object.class.equals(clazz.getSuperclass())){
            putDeclaredFieldsToMap(obj, clazz.getSuperclass(), beanMap);
        }
    }

     /**
      * <desc>
      *      分页条件DTO对象转换
      * <desc/>
      *
      * @param pageDTO 待转换DTO对象
      * @param page 分页对象
      * @return
      * @author Chunjian.G
      * @createDate 2017-10-10
      */
    public static <T extends BaseDTO> Map convertBeanToMapParams(T pageDTO, Page page) throws Exception {
        //将DTO转换为Map
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(pageDTO);
        //分页对象
        if (page == null){
            throw new  Exception("分页查询DTO对象转换失败：Page对象不能为空");
        }
        page.getPage().setPageSize(pageDTO.getPageSize());
        page.getPage().setCurrentPage(pageDTO.getCurrentPage());

        params.put("currentPage", page.getPage().getStartSlip());
        params.put("pageSize", page.getPage().getPageSize());
        return  params;
    }

    /**
     * <desc>
     *      获取批量插入或更新的参数集
     * </desc>
     *
     * @param objs 操作的对象
     * @param saveOrUpdate 插入或更新的标识
     * @param <T>
     * @return
     * @throws Exception
     * @author Jiaqi.X
     * @createDate 2018/02/05
     */
    public static <T> List<Map<String,Object>> durableDataList(List<T> objs,String saveOrUpdate) throws Exception {
        List<Map<String,Object>> datas = new ArrayList<>();
        for(T obj : objs){
            datas.add(durableData(obj,saveOrUpdate));
        }
        return datas;
    }

    /**
     * <desc>
     *      获取插入或更新的参数集
     * </desc>
     *
     * @param obj 待转换的bean
     * @return map
     * @throws Exception
     * @author Jiaqi.X
     * @createDate 2017/09/14
     */
    public static <T> Map durableData(T obj, String saveOrUpdate) throws Exception {
        Map resultMap = new HashMap<>();
        List<String> objFields = null;
        List<Object> objcolumnValue = null;
        List<Map<String, Object>> updates = null;
        try {
            //表名注解
            ItlTables itlTables = obj.getClass().getAnnotation(ItlTables.class);
            resultMap.put("table", itlTables.value());
            Field[] childs = obj.getClass().getDeclaredFields();
            Class superClass = obj.getClass().getSuperclass();
            Field[] supers = superClass.getDeclaredFields();
            //将父子类都添加进list
            List<Field> fields = new ArrayList<>();
            for (Field superField : supers) {
                fields.add(superField);
            }
            for (Field childField : childs) {
                fields.add(childField);
            }
            objFields = new ArrayList<>();
            objcolumnValue = new ArrayList<>();
            updates = new ArrayList<>();
            for (Field field : fields) {
                //列名注解
                ItlField itlField = field.getAnnotation(ItlField.class);
                //跳过非数据库绑定属性字段（如createDate、updateDate）
                if (null == itlField)
                {
                    continue;
                }
                //获取get属性方法名
                String name = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                //获取属性的类型
                String type = field.getGenericType().toString();
                if (saveOrUpdate.equals(PlatformConstants.TABLE_UPDATE)) {
                    if (itlField != null && itlField.value().equals("id") && !itlField.logicKey().equals("key")) {
                        //如果是更新，跳过id
                        continue;
                    }
                    if (itlField != null && itlField.logicKey().equals("key")) {
                        //如果是逻辑主键，添加至resultMap
                        Method m = obj.getClass().getMethod("get" + name);
                        Object value = m.invoke(obj);
                        resultMap.put("logicKeyName", itlField.value());
                        resultMap.put("logicKeyValue", value);
                        continue;
                    }
                }
                //设置需要添加或修改的参数
                setSaveOrUpdateParam(objFields, objcolumnValue, updates, type, field, obj, name, saveOrUpdate);
            }
        } catch (Exception e) {
            throw new Exception("从bean转换为map时异常!", e);
        }
        if (saveOrUpdate.equals("SAVE")) {
            resultMap.put("fields", objFields);
            resultMap.put("columnValue", objcolumnValue);
        } else {
            resultMap.put("list", updates);
        }
        return resultMap;
    }

    /**
     * <desc>
     *      获取字段类型然后获取字段值拼接插入语句
     * </desc>
     *
     * @param {@link java.util.List} objFields  save的列名
     * @param {@link java.util.List} objcolumnValue save的值
     * @param {@link java.util.List} updates 更新的参数集
     * @param {@link java.lang.String}  type 反射字段类型
     * @param {@link java.lang.reflect} f   反射字段
     * @param {@link java.util.List} saveList 插入参数
     * @param {@link java.lang.Object} t  对象
     * @param {@link java.lang.String} name 对象
     * @param {@link java.lang.String} isSave 保存标识
     * @return
     * @author Jiaqi.X
     * @createDate 2017/09/14
     */
    private static void setSaveOrUpdateParam(
            List<String> objFields,
            List<Object> objcolumnValue,
            List<Map<String, Object>> updates,
            String type,
            Field f,
            Object t,
            String name,
            String isSave) {
        Map<String, Object> map = new HashMap<>();
        try {
            //更新时对可以为空字符串或null的字段进行操作
            if (isSave.equals(PlatformConstants.TABLE_UPDATE)) {
                ItlField fruitName = f.getAnnotation(ItlField.class);
                if (fruitName != null && fruitName.notNull().equals("false")) {
                    Method m = t.getClass().getMethod("get" + name);
                    Object value = m.invoke(t);
                    map.put("columnName", fruitName.value());
                    map.put("columnValue", value);
                    updates.add(map);
                    return;
                }
            }
            Method m = t.getClass().getMethod("get" + name);
            //如果type是类类型，则前面包含"class "，后面跟类名
            Object value;
            if (type.equals("class java.lang.String")) {
                //调用getter方法获取属性值
                value = m.invoke(t);
                if (value != null && !value.equals("")) {
                    ItlField fruitName = f.getAnnotation(ItlField.class);
                    if (isSave.equals(PlatformConstants.TABLE_SAVE)) {
                        objFields.add(fruitName.value());
                        objcolumnValue.add(value);
                    } else {
                        map.put("columnName", fruitName.value());
                        map.put("columnValue", value);
                        updates.add(map);
                    }
                    return;
                }
            }
            value = m.invoke(t);
            if (type.equals("int") || value != null) {
                ItlField fruitName = f.getAnnotation(ItlField.class);
                if (isSave.equals(PlatformConstants.TABLE_SAVE)) {
                    objFields.add(fruitName.value());
                    if (type.equals("class java.util.Date")) {
                        objcolumnValue.add(DateUtil.fomatDate((Date) value));
                    } else {
                        objcolumnValue.add(value);
                    }
                } else {
                    map.put("columnName", fruitName.value());
                    if (type.equals("class java.util.Date")) {
                        map.put("columnValue", DateUtil.fomatDate((Date) value));
                    } else {
                        map.put("columnValue", value);
                    }
                    updates.add(map);
                }
            }
        } catch (NoSuchMethodException e) {
            throw new DataAccessException(String.format("【公共部分】拼接sql参数出错:"), e);
        } catch (InvocationTargetException e) {
            throw new DataAccessException(String.format("【公共部分】拼接sql参数出错:"), e);
        } catch (IllegalAccessException e) {
            throw new DataAccessException(String.format("【公共部分】拼接sql参数出错:"), e);
        } catch (Exception e) {
            throw new DataAccessException(String.format("【公共部分】拼接sql参数出错:"), e);
        }
    }


}
